/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.service.core.impl;

import com.blandware.atleap.common.util.PartialCollection;
import com.blandware.atleap.common.util.QueryInfo;
import com.blandware.atleap.common.Constants;
import com.blandware.atleap.model.core.ActionPage;
import com.blandware.atleap.model.core.ContentPage;
import com.blandware.atleap.model.core.Layout;
import com.blandware.atleap.model.core.Page;
import com.blandware.atleap.persistence.core.*;
import com.blandware.atleap.persistence.exception.DeleteException;
import com.blandware.atleap.service.core.PageManager;
import com.blandware.atleap.service.core.UtilManager;
import com.blandware.atleap.service.exception.BeanAlreadyExistsException;
import com.blandware.atleap.service.exception.BeanNotFoundException;
import com.blandware.atleap.service.exception.OwnerNotFoundException;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Iterator;

/**
 * <p>Implementation of PageManager</p>
 * <p><a href="PageManagerImpl.java.html"><i>View Source</i></a>
 * </p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.23 $ $Date: 2008/01/14 15:54:32 $
 */
public class PageManagerImpl extends BaseManagerImpl implements PageManager {

    /**
     * Action page DAO
     */
	protected ActionPageDAO actionPageDAO;
    /**
     * Content page DAO
     */
	protected ContentPageDAO contentPageDAO;
    /**
     * Page DAO
     */
	protected PageDAO pageDAO;
    /**
     * Layout DAO
     */
	protected LayoutDAO layoutDAO;

    /**
     * Util manager to use
     */
    protected UtilManager utilManager;

	/**
	 * Creates new instance of PageManagerImpl
	 */
	public PageManagerImpl() {
	}

    /**
     * Sets DAO to operate with action pages
     *
     * @param actionPageDAO the DAO to set
     */
	public void setActionPageDAO(ActionPageDAO actionPageDAO) {
		this.actionPageDAO = actionPageDAO;
	}

    /**
     * Sets DAO to operate with content pages
     *
     * @param contentPageDAO the DAO to set
     */
	public void setContentPageDAO(ContentPageDAO contentPageDAO) {
		this.contentPageDAO = contentPageDAO;
	}

    /**
     * Sets DAO to operate with pages
     *
     * @param pageDAO the DAO to set
     */
	public void setPageDAO(PageDAO pageDAO) {
		this.pageDAO = pageDAO;
	}

    /**
     * Sets DAO for operating with layouts
     *
     * @param layoutDAO the DAO to set
     */
	public void setLayoutDAO(LayoutDAO layoutDAO) {
		this.layoutDAO = layoutDAO;
	}

    /**
     * Sets util manager to use
     *
     * @param utilManager manager to set
     */
    public void setUtilManager(UtilManager utilManager) {
        this.utilManager = utilManager;
    }

    // P A G E S

	/**
	 * @see com.blandware.atleap.service.core.PageManager#listPages(com.blandware.atleap.common.util.QueryInfo) 
	 */
    public PartialCollection listPages(QueryInfo queryInfo) {
		return pageDAO.listPages(queryInfo);
	}

    // L I N K A B L E   I T E M S

	/**
	 * @see com.blandware.atleap.service.core.PageManager#listLinkableItems(com.blandware.atleap.common.util.QueryInfo) 
	 */
	public PartialCollection listLinkableItems(QueryInfo queryInfo) {
		return pageDAO.listLinkableItems(queryInfo);
	}

	// C O N T E N T    P A G E S

	//~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#createContentPage(com.blandware.atleap.model.core.ContentPage, java.lang.Long)
	 */
	public Long createContentPage(ContentPage contentPage, Long layoutId) throws BeanAlreadyExistsException, BeanNotFoundException {

		if ( log.isDebugEnabled() ) {
			log.debug("Creating new content page...");
		}

		Layout layout = layoutDAO.retrieveLayout(layoutId);

		if ( layout == null ) {
			// layout does not exist
			String errorMessage = "Layout with ID=" + layoutId + " does not exist";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

		if ( pageDAO.hasDuplicates(contentPage) ) {
			throw new BeanAlreadyExistsException("Content page with the same URI already exists");
		}

		// page does not exist so create it
		Long contentPageId = contentPageDAO.createContentPage(contentPage, layout);

		if ( log.isDebugEnabled() ) {
			log.debug("New content page has been created successfully. Its ID is " + contentPageId);
		}
		return contentPageId;
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#retrieveContentPage(java.lang.Long)
	 */
	public ContentPage retrieveContentPage(Long contentPageId) {
		ContentPage contentPage;
		contentPage = contentPageDAO.retrieveContentPage(contentPageId);
		return contentPage;
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#updateContentPage(com.blandware.atleap.model.core.ContentPage, Long layoutId)
	 */
	public void updateContentPage(ContentPage contentPage, Long layoutId) throws BeanAlreadyExistsException, BeanNotFoundException {

        // remove page from cache in order to prevent Hibernate from assigning new version number
		contentPageDAO.removeFromCache(contentPage);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating content page...");
		}

		Layout layout = layoutDAO.retrieveLayout(layoutId);

		if ( layout == null ) {
			// layout does not exist
			String errorMessage = "Layout with ID=" + layoutId + " does not exist";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new OwnerNotFoundException(errorMessage);
		}

		if ( pageDAO.hasDuplicates(contentPage) ) {
			throw new BeanAlreadyExistsException("Content page with the same URI already exists");
		}

		// page with given URI does not exist
        ContentPage oldContentPage = contentPageDAO.retrieveContentPage(contentPage.getId());
        if (oldContentPage != null) {
            String oldUri = oldContentPage.getUri();
            String newUri = contentPage.getUri();
            if (!newUri.equals(oldUri)) {
                utilManager.replaceLinkableObjectUriInLinkedObjects(oldUri, newUri, oldContentPage.getLinkedContentFieldValues(), oldContentPage.getLinkedMenuItems(), Constants.LOCALIZED_URI_PREFIX, false);
            }
            contentPageDAO.removeFromCache(oldContentPage);
        }

		contentPageDAO.updateContentPage(contentPage, layout);

		if ( log.isDebugEnabled() ) {
			log.debug("Content page was updated successfully.");
		}
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#deleteContentPage(java.lang.Long)
	 */
	public void deleteContentPage(Long contentPageId) throws BeanNotFoundException, DeleteException {

		ContentPage contentPage = contentPageDAO.retrieveContentPage(contentPageId);
		if ( contentPage == null ) {
			// content page does not exist
			String errorMessage = "Content page with ID=" + contentPageId + " does not exist";
			throw new BeanNotFoundException(errorMessage);
		}

		contentPageDAO.deleteContentPage(contentPage);
		if ( log.isDebugEnabled() ) {
			log.debug("Deleted content page: ID=" + contentPageId);
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#listContentPages(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listContentPages(QueryInfo queryInfo) {
		return contentPageDAO.listContentPages(queryInfo);
	}

    /**
     * @see com.blandware.atleap.service.core.PageManager#performContentPagesActivityCheck() 
     */
    public void performContentPagesActivityCheck() {
		if ( log.isInfoEnabled() ) {
			log.info("Performing content pages activation check...");
		}
		Date today = new Date();
        List unpublishedCPs = contentPageDAO.findUnpublishedContentPages(today);
		if ( log.isInfoEnabled() ) {
			log.info("Number of content pages to set active: " + unpublishedCPs.size());
		}
		for ( Iterator i = unpublishedCPs.iterator(); i.hasNext(); ) {
			ContentPage contentPage = (ContentPage) i.next();
			contentPage.setActive(Boolean.TRUE);
		}

		List expiredCPs = contentPageDAO.findExpiredContentPages(today);
		if ( log.isInfoEnabled() ) {
			log.info("Number of content pages to set inactive: " + expiredCPs.size());
		}
		for ( Iterator i = expiredCPs.iterator(); i.hasNext(); ) {
			ContentPage contentPage = (ContentPage) i.next();
			contentPage.setActive(Boolean.FALSE);
		}
    }

    // ~ Finders ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#findContentPageByUri(java.lang.String)
	 */
	public ContentPage findContentPageByUri(String contentPageUri) {
		ContentPage contentPage;
		contentPage = contentPageDAO.findContentPageByUri(contentPageUri);
		return contentPage;
	}

	// A C T I O N    P A G E S

	//~ CRUD Methods ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#createActionPage(com.blandware.atleap.model.core.ActionPage)
	 */
	public Long createActionPage(ActionPage actionPage) throws BeanAlreadyExistsException {

		if ( log.isDebugEnabled() ) {
			log.debug("Creating new action page...");
		}

		if ( pageDAO.hasDuplicates(actionPage) ) {
			throw new BeanAlreadyExistsException("Action page with the same URI already exists");
		}

		// page does not exist
		Long actionPageId = actionPageDAO.createActionPage(actionPage);
		if ( log.isDebugEnabled() ) {
			log.debug("New action page has been created successfully. Its ID is " + actionPageId);
		}
		return actionPageId;
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#retrieveActionPage(java.lang.Long)
	 */
	public ActionPage retrieveActionPage(Long actionPageId) {
		return actionPageDAO.retrieveActionPage(actionPageId);
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#updateActionPage(com.blandware.atleap.model.core.ActionPage)
	 */
	public void updateActionPage(ActionPage actionPage) throws BeanAlreadyExistsException {

		actionPageDAO.removeFromCache(actionPage);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating action page...");
		}

		if ( pageDAO.hasDuplicates(actionPage) ) {
			throw new BeanAlreadyExistsException("Action page with the same URI already exists");
		}

		// page with that URI does not exist
        ActionPage oldActionPage = actionPageDAO.retrieveActionPage(actionPage.getId());
        if (oldActionPage != null) {
            String oldUri = oldActionPage.getUri();
            String newUri = actionPage.getUri();
            if (!newUri.equals(oldUri)) {
                utilManager.replaceLinkableObjectUriInLinkedObjects(oldUri, newUri, oldActionPage.getLinkedContentFieldValues(), oldActionPage.getLinkedMenuItems(), Constants.LOCALIZED_URI_PREFIX, false);
            }
            actionPageDAO.removeFromCache(oldActionPage);
        }

		actionPageDAO.updateActionPage(actionPage);

		if ( log.isDebugEnabled() ) {
			log.debug("Action page was updated successfully.");
		}
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#deleteActionPage(java.lang.Long)
	 */
	public void deleteActionPage(Long actionPageId) throws DeleteException, BeanNotFoundException {
		ActionPage actionPage = actionPageDAO.retrieveActionPage(actionPageId);
		if ( actionPage == null ) {
			String errorMessage = "No content resource with ID=" + actionPage + "could be found";
			throw new BeanNotFoundException(errorMessage);
		}

		actionPageDAO.deleteActionPage(actionPage);

		if ( log.isDebugEnabled() ) {
			log.debug("Deleted action page: ID=" + actionPageId);
		}
	}

	// ~ Additional methods ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#listActionPages(com.blandware.atleap.common.util.QueryInfo)
	 */
	public PartialCollection listActionPages(QueryInfo queryInfo) {
		return actionPageDAO.listActionPages(queryInfo);
	}

	// ~ Finders ================================================================

	/**
	 * @see com.blandware.atleap.service.core.PageManager#findActionPageByUri(java.lang.String)
	 */
	public ActionPage findActionPageByUri(String actionPageUri) {
		ActionPage actionPage;
		actionPage = actionPageDAO.findActionPageByUri(actionPageUri);
		return actionPage;
	}


	// P A G E S

	/**
	 * @see com.blandware.atleap.service.core.PageManager#findPageByUri(java.lang.String)
	 */
	public Page findPageByUri(String pageUri) {
		Page page;
		page = pageDAO.findPageByUri(pageUri);
		return page;
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#retrievePage(java.lang.Long)
	 */
	public Page retrievePage(Long pageId) {
		Page page;
		page = pageDAO.retrievePage(pageId);
		return page;
	}

	/**
	 * @see com.blandware.atleap.service.core.PageManager#updatePage(com.blandware.atleap.model.core.Page)
	 */
	public void updatePage(Page page) throws BeanAlreadyExistsException {

		pageDAO.removeFromCache(page);

		if ( log.isDebugEnabled() ) {
			log.debug("Updating page...");
		}

		if ( pageDAO.hasDuplicates(page) ) {
			throw new BeanAlreadyExistsException("Page with the same URI already exists");
		}

		// page with that URI does not exist
        Page oldPage = pageDAO.retrievePage(page.getId());
        if (oldPage != null) {
            String oldUri = oldPage.getUri();
            String newUri = page.getUri();
            if (!newUri.equals(oldUri)) {
                utilManager.replaceLinkableObjectUriInLinkedObjects(oldUri, newUri, oldPage.getLinkedContentFieldValues(), oldPage.getLinkedMenuItems(), Constants.LOCALIZED_URI_PREFIX, false);
            }
            pageDAO.removeFromCache(oldPage);
        }

		pageDAO.updatePage(page);

		if ( log.isDebugEnabled() ) {
			log.debug("Page was updated successfully.");
		}
	}

    /**
     * @see com.blandware.atleap.service.core.PageManager#listPagesFetching()
     */
    public Collection listPagesFetching() {
        return pageDAO.listPagesFetching();
    }

    /**
     * @see com.blandware.atleap.service.core.PageManager#getLastPages(com.blandware.atleap.common.util.QueryInfo)
     */
    public List getLastPages(QueryInfo queryInfo) {
        return pageDAO.getLastPages(queryInfo);
    }

    /**
     * @see com.blandware.atleap.service.core.PageManager#getPagesAnnotations(java.util.List, String)
     */
    public List getPagesAnnotations(List list, String localeIdentifier) {
        return pageDAO.getPagesAnnotations(list, localeIdentifier);
    }

    /**
	 * @see com.blandware.atleap.service.core.PageManager#increaseUsageCounter(java.lang.Long, java.lang.Integer)
	 */
	public void increaseUsageCounter(Long pageId, Integer value) throws BeanNotFoundException {
		Page page = pageDAO.retrievePage(pageId);

		if ( page == null ) {
			// page does not exist
			String errorMessage = "Page with ID=" + pageId + " does not exist";
			if ( log.isErrorEnabled() ) {
				log.error(errorMessage);
			}
			throw new BeanNotFoundException(errorMessage);
		}

		page.setUsageCounter(new Integer(page.getUsageCounter().intValue() + value.intValue()));
		pageDAO.updatePage(page);
	}
}
